iT邦幫忙

2025 iThome 鐵人賽

DAY 26
0
佛心分享-IT 人自學之術

30 天從 Python 轉職場 C# 新手入門系列 第 26

Day26-Routing 與 Controller(ASP.NET Core Web API 教學)

  • 分享至 

  • xImage
  •  

前言

在昨天的文章中,我們已經建立了基本的 Web API 專案,並理解了 API 的基本運作方式。今天要深入探討的是 Routing(路由)與 Controller(控制器) —— 這是 ASP.NET Core Web API 的靈魂所在。


Routing 是什麼?

Routing(路由)決定了使用者請求的 URL 該如何被導向到對應的 Controller 與 Action,簡單來說,當使用者呼叫 https://localhost:5001/api/products/1 時,框架會透過 Routing Table(路由表) 找到哪個控制器的哪個方法要被執行。
首先可以看到在 ASP.NET Core 使用 Endpoint Routing,在 Program.cs 中通常可以看到這樣的設定:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();

app.MapControllers(); // 啟用屬性路由
app.Run();

這行 app.MapControllers() 代表應用程式啟用 Attribute Routing(屬性路由),也就是透過 Controller 上的屬性 [Route()] 來定義 URL 規則。


Controller 與基本路由

建立一個最簡單的 Controller:

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "Keyboard", "Mouse", "Monitor" };
    }

    [HttpGet("{id}")]
    public string Get(int id)
    {
        return $"Product ID: {id}";
    }
}

當我們執行後,可以使用以下路徑呼叫:

方法 路徑 說明
GET /api/products 取得所有產品
GET /api/products/1 取得 ID=1 的產品

Attribute Routing(屬性路由)

屬性路由是目前最常用的方式,它允許在控制器或方法上直接定義 URL 規則:

[Route("api/products")]
public class ProductsController : ControllerBase
{
    [HttpGet]               // GET api/products
    public IEnumerable<Product> GetAll() => _repository.GetAll();

    [HttpGet("{id}")]       // GET api/products/5
    public Product GetById(int id) => _repository.Get(id);

    [HttpPost]              // POST api/products
    public void Create(Product product) => _repository.Add(product);
}

這樣可以讓路由與程式邏輯清楚地綁在一起,維護性高,也容易閱讀。


路由參數與約束(Route Constraints)

路由參數可以限制輸入格式,避免錯誤請求。舉例來說:

[HttpGet("{id:int}")]
public IActionResult GetById(int id) => Ok($"Product ID: {id}");

[HttpGet("{name:alpha}")]
public IActionResult GetByName(string name) => Ok($"Product Name: {name}"
範例路由 約束說明
{id:int} 必須為整數
{name:alpha} 必須為字母組成
{price:decimal} 必須為數字(含小數點)
{date:datetime} 必須是有效日期格式

可選參數與預設值

有時候我們希望參數是可選的:

[HttpGet("{id?}")]
public IActionResult Get(int? id)
{
    if (id == null)
        return Ok("All Products");
    else
        return Ok($"Product {id}");
}

或者給定預設值:

[HttpGet("{category=general}")]
public IActionResult GetCategory(string category) => Ok($"Category: {category}");

組合路由(Combining Routes)

屬性路由可以互相組合,控制器定義一個基本路由,方法再延伸:

[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll() => Ok("All Orders");

    [HttpGet("pending")]
    public IActionResult GetPending() => Ok("Pending Orders");

    [HttpGet("{id}/details")]
    public IActionResult GetDetails(int id) => Ok($"Details for {id}");
}

這樣可產生:

  • /api/orders
  • /api/orders/pending
  • /api/orders/1/details

URL 生成(URL Generation)

有時候,我們需要從程式中生成對應的 URL(而不是手寫),例如:

[HttpGet("{id}", Name = "GetProductById")]
public IActionResult GetById(int id) => Ok($"Product {id}");

[HttpPost]
public IActionResult Create(Product product)
{
    // 透過路由名稱生成 URL
    var url = Url.Link("GetProductById", new { id = product.Id });
    return Created(url!, product);
}

這樣當新增成功後,系統會自動回傳新建資源的完整 URL。

Areas(區域路由)

當專案變大時,可以利用 Areas 來分區管理不同模組的 Controller。

[Area("Admin")]
[Route("api/[area]/[controller]")]
public class UsersController : ControllerBase
{
    [HttpGet]
    public IActionResult GetUsers() => Ok("Admin Users");
}

呼叫路徑就會是:
/api/admin/users
這對於大型專案的模組化開發非常實用。


可以根據今天的內容做一個大致的重點整理:

主題 重點
Routing 決定請求 URL 對應的 Controller 與 Action
Attribute Routing 在控制器或方法上以屬性方式定義路由
Route Constraints 限制參數型態(如 int、alpha、datetime)
URL Generation Url.Link() 自動生成對應路由 URL
Areas 用於大型專案的模組化路由管理

結語

Routing 是 API 架構的基礎,決定了如何將請求導向正確的邏輯。理解 Attribute Routing、參數約束 與 Areas,不僅能讓 API 架構更清晰,也讓維護與擴充變得更輕鬆。
明天,我們將進一步探討 Model Binding 與 Validation(資料繫結與驗證),讓 API 不只是能運作,還能正確處理輸入資料!


上一篇
Day25-ASP.NET Core 入門:建立第一個 Web API
系列文
30 天從 Python 轉職場 C# 新手入門26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言